<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>深浅拷贝_Object.assign()</title>
</head>
<body>
    <script>
        // 引用类型和基础类型
        // 基础类型: 数字, 字符串, 布尔, null, undefined  - 具体的值
        // 引用类型: 数组, 对象    (高级话: 万物皆对象都是new出来的)
        
        // 本质区别:
        // 基础类型的值 - 直接保存在栈区
        // 引用类型的值 - 保存在堆区

            // 内存: 文件是存储在硬盘上的, 运行某个文件, js引擎会把代码里的变量赋予到内存里
            // CPU只会调度内存里的变量和值来计算结果, 显示到页面上 (计算机组成原理)

            // 内存分类: 栈区, 堆区, 常量区
            // 内存里保存的都是变量的地址, 和值的地址  (cpu调度都是寻找内存地址然后找到具体的值)

            // 栈和堆区别:
            // 栈: 变量和基础类型的地址 var a = 10;  a会在栈区开个地址, 保存10
            // 堆: 引用类型值的地址 
            //    var obj = {}; // obj变量在栈区开个地址, 保存{}的堆地址
            //    {}相当于new Object() 在堆开辟一个地址空间

        // 口诀: 如果一个变量保存的是引用类型, 那保存的是堆地址

        // = 赋值
        // var a = 10;
        // var b = a;
        // a = 100;
        // console.log(a, b); // 100 10

        // let obj = {a: 10, b: 20} // 对象堆地址赋予给obj
        // let newObj = obj; // 堆地址赋予给了另外一个变量 (newObj和obj指向的是同一个堆空间的地址-同一个对象)
        // obj.a = 100;
        // console.log(newObj); // {a: 100 b: 20 }

        // =口诀: 把右侧的值赋予给左侧的变量 (引用类型原地是堆地址)

        // 拷贝
        // 只发生在引用类型的时候, 为了彻底让2个对象对立关系
        // 尽量去mdn网站(官方) - 博客是程序员自己合计的(不一定100%准确)
        // 拷贝口诀: 把一个对象里的key+value, 拷贝给另外一个对象里去赋予key+value

        // 浅拷贝口诀: 只拷贝第一层的key+value

        // 例: 
        // let obj = {a: 10, b: 20} // 原来的对象
        // let newObj = {}; // 新的对象

        
        // for (let key in obj) {
        //     newObj[key] = obj[key]
        // }

        // obj.a = 100;
        // console.log(newObj);

        
        // 问题: 如果第二层是个引用类型,还是会互相引用(没有彻底脱离关系)
        // let obj = {a: 10, b: 20, c: {firstName: "李"}};
        // let newObj = {};

        // for (let key in obj) {
        //     newObj[key] = obj[key]
        // }

        // obj.c.firstName = "王";
        // console.log(newObj);


        // 深拷贝口诀: 递归拷贝所有层的引用类型 - 彻底让2个对象之间毫无关联
        let obj = {a: 10, b: 20, c: {firstName: "李"}};
        let newObj = {};

        deepClone(newObj, obj);

        obj.c.firstName = "王";
        console.log(newObj);



        function deepClone(newObj, oldObj){
            for (var k in oldObj) {
                var value = oldObj[k];
                if (value instanceof Array) {
                    newObj[k] = [];
                    deepClone(newObj[k], value);
                } else if (value instanceof Object) { // 如果当前的值又是个对象-把这个对象看成像oldObj一样, 是不是要调用deepClone啊
                // 那再给当前的key, 一个新的对象(相当于newObj一样), 再传入进deepClone里就ok了
                    newObj[k] = {};
                    deepClone(newObj[k], value);
                }
                else {
                    newObj[k] = value;
                }
            }
        }
    </script>
</body>
</html>